import com.intellij.database.editor.DatabaseEditorHelper;
import com.intellij.database.model.DasNamespace;
import com.intellij.database.psi.DbElement;
import com.intellij.database.psi.DbNamespaceImpl;
import com.intellij.database.util.DasUtil;
import com.intellij.notification.NotificationType;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.LangDataKeys;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import enums.ColumnType;
import eventlog.MyNotifier;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import util.ChooseWrapper;
import util.DataDiff;
import util.PluginExistsUtils;
import util.SqlUtil;

import java.io.*;
import java.util.Map;
import java.util.StringJoiner;

public class GenerateSqlAction extends AnAction implements DumbAware {
    private static final Logger logger = LoggerFactory.getLogger(GenerateSqlAction.class);

    @Override
    public void actionPerformed(AnActionEvent e) {
        Project project = e.getProject();
        PsiElement[] data = e.getData(LangDataKeys.PSI_ELEMENT_ARRAY);
        if (data == null) {
            MyNotifier.notifyError(project, NotificationType.ERROR, "Did Not Choose Or Choose Wrong");
            return;
        }
        if (data.length != 2) {
            MyNotifier.notifyError(project, NotificationType.ERROR, "Must Choose Two");
            return;
        }

        if (!(data[0] instanceof DbNamespaceImpl) || !(data[1] instanceof DbNamespaceImpl)) {
            MyNotifier.notifyError(project, NotificationType.ERROR, "Go To Select The Schema");
            return;
        }

        ChooseWrapper chooseWrapper = new ChooseWrapper(project);
        chooseWrapper.setData(data);
        chooseWrapper.show();
        if (chooseWrapper.getExitCode() != Messages.YES) {
            return;
        }
        PsiElement[] psi = chooseWrapper.getPsi();
        DbNamespaceImpl source = (DbNamespaceImpl) psi[0];
        DbNamespaceImpl target = (DbNamespaceImpl) psi[1];
        Map<String, Map<String, Map<ColumnType, Object>>> sourceData = SqlUtil.getData(source);
        Map<String, Map<String, Map<ColumnType, Object>>> targetData = SqlUtil.getData(target);

        Map<String, Object> map = DataDiff.diffTablesOrViews(sourceData, targetData);
        StringJoiner stringJoiner = SqlUtil.getDiffTables(psi[0], map);

        DbElement dbElement = (DbElement) psi[1];
        VirtualFile file = DatabaseEditorHelper.createNewConsoleVirtualFile(dbElement.getDataSource());
        DatabaseEditorHelper.openConsoleForFile(dbElement.getProject(),
                dbElement.getDataSource(),
                DasUtil.getParentOfClass(dbElement, DasNamespace.class, false), file);

        try {
            String canonicalPath = file.getCanonicalPath();
//            writeFile(new File(canonicalPath),stringJoiner.toString());
            FileUtil.writeToFile(new File(canonicalPath), stringJoiner.toString());

        } catch (IOException ex) {
            logger.error("Diff-GenerateSql-FILE-APPEND-STRING-ERROR:{}", ExceptionUtils.getStackTrace(ex));
        }
    }

    @Override
    public void update(@NotNull AnActionEvent e) {
        PluginExistsUtils.existsDbTools(e);
    }

    @Override
    public boolean isDumbAware() {
        return super.isDumbAware();
    }

    private void writeFile(File file, String content) throws IOException {
        FileOutputStream fos = new FileOutputStream(file, false);
        OutputStreamWriter osw = new OutputStreamWriter(fos);

        BufferedWriter bw = new BufferedWriter(osw);
        Throwable throwable = null;

        try {
            bw.write(content);
        } catch (Throwable var16) {
            throwable = var16;
            throw var16;
        } finally {
            if (throwable != null) {
                try {
                    bw.close();
                } catch (Throwable cl) {
                    throwable.addSuppressed(cl);
                }
            } else {
                bw.close();
            }
        }
    }
}

